home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pico / os_os2.c < prev    next >
C/C++ Source or Header  |  1996-05-30  |  32KB  |  1,597 lines

  1. /*
  2.  * $Id: os_os2.c,v 4.8 1996/05/31 00:08:47 mikes Exp $
  3.  *
  4.  * Program:    Operating system dependent routines - OS/2 Text mode
  5.  *
  6.  *
  7.  * Michael Seibel
  8.  * Networks and Distributed Computing
  9.  * Computing and Communications
  10.  * University of Washington
  11.  * Administration Builiding, AG-44
  12.  * Seattle, Washington, 98195, USA
  13.  * Internet: mikes@cac.washington.edu
  14.  *
  15.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  16.  *
  17.  *
  18.  * Pine and Pico are registered trademarks of the University of Washington.
  19.  * No commercial use of these trademarks may be made without prior written
  20.  * permission of the University of Washington.
  21.  * 
  22.  * Pine, Pico, and Pilot software and its included text are Copyright
  23.  * 1989-1996 by the University of Washington.
  24.  * 
  25.  * The full text of our legal notices is contained in the file called
  26.  * CPYRIGHT, included with this distribution.
  27.  *
  28.  *
  29.  * Notes:
  30.  *      - mouse support added (mss, 921215)
  31.  *
  32.  *  Portions of this code derived from MicroEMACS 3.10:
  33.  *
  34.  *    OS2.C:    Operating specific I/O and Spawning functions
  35.  *            under the OS/2 operating system
  36.  *            for MicroEMACS 3.10
  37.  *            (C)opyright 1988 by Daniel M. Lawrence
  38.  *
  39.  */
  40.  
  41. #include     <stdio.h>
  42. #include    <errno.h>
  43. #include    <signal.h>
  44. #include    <setjmp.h>
  45. #include    <time.h>
  46. #include    <fcntl.h>
  47. #include    <io.h>
  48. #include    <process.h>
  49.  
  50. #include    "osdep.h"
  51. #include    "estruct.h"
  52. #include    "pico.h"
  53. #include    "edef.h"
  54.  
  55.  
  56. /*
  57.  * Internal functions...
  58.  */
  59. int   checkmouse();
  60. void  invert_label(int, MENUITEM *);
  61. int   enhanced_keybrd(void);
  62. int   dont_interrupt(void);
  63. int   interrupt_ok(void);
  64. int   kbseq(int *);
  65. int   specialkey(unsigned int);
  66. void  do_alarm_signal(void);
  67. void  do_hup_signal(int sig);
  68. char *pfnexpand(char *, int);
  69. int   ssleep(long);
  70. void  mouseon();
  71. void  mouseoff();
  72.  
  73. void turnmouseoff();
  74.  
  75. /*
  76.  * Useful global def's
  77.  */
  78.  
  79. int timeout =0;
  80. static    int oldbut;            /* Previous state of mouse buttons */
  81. static  int enhncd;                       /* Enhanced keyboard */
  82. static  KBDINFO initialKbdInfo;
  83.  
  84. #ifdef    MOUSE
  85. /*
  86.  * Useful definitions...
  87.  */
  88. static int mexist = 0;        /* is the mouse driver installed? */
  89. static int nbuttons;        /* number of buttons on the mouse */
  90. static unsigned mnoop;
  91. static unsigned char okinfname[32] = {
  92.       0,    0,             /* ^@ - ^G, ^H - ^O  */
  93.       0,    0,            /* ^P - ^W, ^X - ^_  */
  94.       0,    0x17,        /* SP - ' ,  ( - /   */
  95.       0xff, 0xe4,        /*  0 - 7 ,  8 - ?   */
  96.       0x7f, 0xff,        /*  @ - G ,  H - O   */
  97.       0xff, 0xe9,        /*  P - W ,  X - _   */
  98.       0x7f, 0xff,        /*  ` - g ,  h - o   */
  99.       0xff, 0xf6,        /*  p - w ,  x - DEL */
  100.       0,    0,             /*  > DEL   */
  101.       0,    0,            /*  > DEL   */
  102.       0,    0,             /*  > DEL   */
  103.       0,    0,             /*  > DEL   */
  104.       0,    0             /*  > DEL   */
  105. };
  106. #endif
  107.  
  108.  
  109. static void set_kbd(int state)
  110. {
  111.   KBDINFO kbdInfo = initialKbdInfo;
  112.   if (state)
  113.   {
  114.     kbdInfo.fsMask &= ~(0x0001|0x0008|0x0100); /* echo,cooked */
  115.     kbdInfo.fsMask |= (0x0002|0x0004|0x0100);  /* noecho,raw,shift-rpt on */
  116.   }
  117.   KbdSetStatus(&kbdInfo, 0);
  118. }
  119.  
  120. /*
  121.  * DISable ctrl-break interruption
  122.  */
  123. dont_interrupt()
  124. {
  125.   signal (SIGINT, SIG_IGN);
  126.   signal (SIGBREAK, SIG_IGN);
  127.   set_kbd(1);
  128. }
  129.  
  130. /*
  131.  * re-enable ctrl-break interruption
  132.  */
  133. interrupt_ok()
  134. {
  135.   set_kbd(0);
  136.   signal (SIGINT, SIG_DFL);
  137.   signal (SIGBREAK, SIG_DFL);
  138. }
  139.  
  140.  
  141. /*
  142.  * return true if an enhanced keyboard is present
  143.  */
  144. enhanced_keybrd()
  145. {
  146.   return(1);
  147. }
  148.  
  149.  
  150. /*
  151.  * This function is called once to set up the terminal device streams.
  152.  */
  153. ttopen()
  154. {
  155.   initialKbdInfo.cb = sizeof(initialKbdInfo);
  156.   KbdGetStatus(&initialKbdInfo, 0);
  157.   dont_interrupt();            /* don't allow interrupt */
  158.   enhncd = enhanced_keybrd();        /* check for extra keys */
  159. #if    MOUSE
  160.   init_mouse();
  161. #else    /* !MOUSE */
  162.   mexist = 0;
  163. #endif    /* MOUSE */
  164.   return(1);
  165. }
  166.  
  167. #ifdef    MOUSE
  168. HMOU Mouse_Handle =(HMOU)-1;
  169. #ifdef FASTVIO
  170. int mouse_state =0;
  171. #endif
  172.  
  173. /* 
  174.  * init_mouse - check for and initialize mouse driver...
  175.  */
  176. init_mouse()
  177. {
  178.   if (Mouse_Handle==(HMOU)-1) {
  179.     int rc = MouOpen(NULL, &Mouse_Handle);
  180.     mexist=0;
  181.     if (rc)
  182.       return(FALSE);
  183.     mexist=1;
  184.     nbuttons=2;
  185.     MouFlushQue(Mouse_Handle);
  186.     turnmouseoff();
  187.   }
  188.   return(TRUE);
  189. }
  190.  
  191. static int mouchk()
  192. {
  193.   if (mexist)
  194.     return (Mouse_Handle==(HMOU)-1) ? init_mouse() : TRUE;
  195.   return FALSE;
  196. }
  197.  
  198. deinit_mouse()
  199. {
  200.   turnmouseoff();
  201. }
  202.  
  203.  
  204. /*
  205.  * mouseon - call made available for programs calling pico to turn ON the
  206.  *           mouse cursor.
  207.  */
  208. void
  209. mouseon()
  210. {
  211.   /* Show Cursor */
  212.   if (mouchk() && !mouse_state) {
  213. #ifdef FASTVIO
  214.     mouse_state=TRUE;
  215.     vidUpdate();
  216. #else
  217.     MouDrawPtr(Mouse_Handle);
  218. #endif
  219.   }
  220. }
  221.  
  222. void
  223. turnmouseoff()
  224. {
  225.   static NOPTRRECT r = { 0, 0, (USHORT)-1, (USHORT)-1 };
  226.   if (r.cRow == (USHORT)-1) {
  227.     VIOMODEINFO mi;
  228.     mi.cb = sizeof mi;
  229.     VioGetMode(&mi, 0);
  230.     r.cRow = mi.row-1;
  231.     r.cCol = mi.col-1;
  232.   }
  233.   /* Hide Cursor */
  234.   MouRemovePtr(&r, Mouse_Handle);
  235.   mouse_state=FALSE;
  236. }
  237.  
  238. /*
  239.  * mouseon - call made available for programs calling pico to turn OFF the
  240.  *           mouse cursor.
  241.  */
  242. void
  243. mouseoff()
  244. {
  245. #ifdef FASTVIO
  246.   /* This is ignored if in FASTVIO mode */
  247. #else
  248.   if (mouchk()) {
  249.     turnmouseoff();
  250.   }
  251. #endif
  252. }
  253. #endif
  254.  
  255.  
  256. /*
  257.  * This function gets called just before we go back home to the command
  258.  * interpreter.
  259.  */
  260. ttclose()
  261. {
  262.   if(!Pmaster)
  263.     interrupt_ok();
  264. #ifdef MOUSE
  265.   deinit_mouse();
  266. #endif
  267.   return(1);
  268. }
  269.  
  270.  
  271. /*
  272.  * Flush terminal buffer. Does real work where the terminal output is buffered
  273.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  274.  */
  275. ttflush()
  276. {
  277.   return(1);
  278. }
  279.  
  280.  
  281. /*
  282.  * specialkey - return special key definition
  283.  */
  284. specialkey(kc)
  285. unsigned  kc;
  286. {
  287.   switch(kc){
  288.   case 0x3b00 : return(F1);
  289.   case 0x3c00 : return(F2);
  290.   case 0x3d00 : return(F3);
  291.   case 0x3e00 : return(F4);
  292.   case 0x3f00 : return(F5);
  293.   case 0x4000 : return(F6);
  294.   case 0x4100 : return(F7);
  295.   case 0x4200 : return(F8);
  296.   case 0x4300 : return(F9);
  297.   case 0x4400 : return(F10);
  298.   case 0x8500 : return(F11);
  299.   case 0x8600 : return(F12);
  300.   case 0x4800 : return(K_PAD_UP);
  301.   case 0x5000 : return(K_PAD_DOWN);
  302.   case 0x4b00 : return(K_PAD_LEFT);
  303.   case 0x4d00 : return(K_PAD_RIGHT);
  304.   case 0x4700 : return(K_PAD_HOME);
  305.   case 0x4f00 : return(K_PAD_END);
  306.   case 0x4900 : return(K_PAD_PREVPAGE);
  307.   case 0x5100 : return(K_PAD_NEXTPAGE);
  308.   case 0x5300 : return(K_PAD_DELETE);
  309.   case 0x48e0 : return(K_PAD_UP);            /* grey key version */
  310.   case 0x50e0 : return(K_PAD_DOWN);        /* grey key version */
  311.   case 0x4be0 : return(K_PAD_LEFT);        /* grey key version */
  312.   case 0x4de0 : return(K_PAD_RIGHT);        /* grey key version */
  313.   case 0x47e0 : return(K_PAD_HOME);        /* grey key version */
  314.   case 0x4fe0 : return(K_PAD_END);        /* grey key version */
  315.   case 0x49e0 : return(K_PAD_PREVPAGE);        /* grey key version */
  316.   case 0x51e0 : return(K_PAD_NEXTPAGE);        /* grey key version */
  317.   case 0x53e0 : return(K_PAD_DELETE);        /* grey key version */
  318.   default     : return(NODATA);
  319.   }
  320. }
  321.  
  322.  
  323. /*
  324.  * Read a character from the terminal, performing no editing and doing no echo
  325.  * at all. Also mouse events are forced into the input stream here.
  326.  */
  327. ttgetc()
  328. {
  329.   int key = kbd_getkey();
  330.   return key ? key : NODATA;
  331. }
  332.  
  333.  
  334. /*
  335.  * ctrlkey - used to check if the key hit was a control key.
  336.  */
  337. ctrlkey()
  338. {
  339.   return !!(kbd_shift() & KBDSTF_CONTROL);
  340. }
  341.  
  342.  
  343. /*
  344.  * win_multiplex - give OS/2 a shot at the CPU
  345.  */
  346. win_multiplex()
  347. {
  348.   DosSleep(32);
  349. }
  350.  
  351.  
  352. /*
  353.  * Read in a key.
  354.  * Do the standard keyboard preprocessing. Convert the keys to the internal
  355.  * character set.  Resolves escape sequences and returns no-op if global
  356.  * timeout value exceeded.
  357.  */
  358. GetKey()
  359. {
  360.   unsigned ch = 0, lch, intrupt = 0;
  361.   long timein;
  362.  
  363.   vidUpdate();
  364.   if(mexist || timeout) {
  365.     timein = time(0L);
  366. #ifdef    MOUSE
  367.     mouseon();        /* Show Cursor */
  368. #endif
  369.     while(!kbd_ready()) {
  370. #if    MOUSE
  371.       if(timeout && time(0L) >= timein+timeout){
  372.     mouseoff();        /* Hide Cursor */
  373.     return(NODATA);
  374.       }
  375.  
  376.       if(checkmouse(&ch,0,0,0)){        /* something happen ?? */
  377.     mouseoff();        /* Hide Cursor */
  378.     curwp->w_flag |= WFHARD;
  379.     return(ch);
  380.       }
  381. #else
  382.       if(time(0L) >= timein+timeout) {
  383.     mouseoff();        /* Hide Cursor */
  384.     return(NODATA);
  385.       }
  386. #endif    /* MOUSE */
  387.  
  388.       /*
  389.        * Surrender the CPU...
  390.        */
  391.       win_multiplex();
  392.     }
  393. #ifdef    MOUSE
  394.     mouseoff();        /* Hide Cursor */
  395. #endif    /* MOUSE */
  396.   }
  397.  
  398.   ch = (*term.t_getchar)();
  399.   lch = (ch&0xff);
  400.   return((lch && (lch != 0xe0 || !(ch & 0xff00))) 
  401.          ? (lch < ' ') ? (CTRL|(lch + '@')) 
  402.          : (lch == ' ' && ctrlkey()) ? (CTRL|'@') : lch
  403.          : specialkey(ch));
  404. }
  405.  
  406.  
  407. #if    MOUSE
  408. /* 
  409.  * checkmouse - look for mouse events in key menu and return 
  410.  *              appropriate value.
  411.  */
  412. int
  413. checkmouse(ch, down, xxx, yyy)
  414. unsigned *ch;
  415. int down, xxx, yyy;
  416. {
  417.   MOUQUEINFO qi;
  418.  
  419.   if(!mouchk())
  420.     return(FALSE);
  421.  
  422.   if (MouGetNumQueEl(&qi, Mouse_Handle)==0 && qi.cEvents)
  423.   {
  424.     MOUEVENTINFO m;
  425.     USHORT w = MOU_NOWAIT;
  426.  
  427.     /* check to see if any mouse buttons are different */
  428.     if (MouReadEventQue(&m, &w, Mouse_Handle)==0)
  429.     {
  430.       int k;
  431.       int rv = 0;
  432.       int button = M_BUTTON_LEFT;
  433.       int newbut = ((m.fs & 4)?1:0) | ((m.fs & 16)?2:0) | ((m.fs & 64)?4:0);
  434.  
  435.       /* only notice button changes */
  436.       if (oldbut == newbut)
  437.     return(FALSE);
  438.  
  439.       for (k=1; k != (1 << nbuttons); k <<= 1) {
  440.     /* For each button on the mouse */
  441.     if ((oldbut&k) != (newbut&k)) {
  442.       if(k == 1){
  443.         static int oindex;
  444.         int i = 0;
  445.         MENUITEM *mp;
  446.  
  447.         if(newbut&k)            /* button down */
  448.           oindex = -1;
  449.  
  450.         for(mp = mfunc; mp; mp = mp->next)
  451.           if(mp->action && M_ACTIVE(m.row, m.col, mp))
  452.         break;
  453.  
  454.         if(mp){
  455.           unsigned long r;
  456.           
  457.           r = (*mp->action)((newbut&k) ? M_EVENT_DOWN : M_EVENT_UP,
  458.                 m.row, m.col, button, 0);
  459.           if(r & 0xffff){
  460.         *ch = (unsigned)((r>>16)&0xffff);
  461.         rv  = TRUE;
  462.           }
  463.         }
  464.         else{
  465.           while(1){    /* see if we understand event */
  466.         if(i >= 12){
  467.           i = -1;
  468.           break;
  469.         }
  470.         
  471.         if(M_ACTIVE(m.row, m.col, &menuitems[i]))
  472.           break;
  473.         
  474.         i++;
  475.           }
  476.           
  477.           if(newbut&k){            /* button down */
  478.         oindex = i;            /* remember where */
  479.         if(i != -1) {            /* invert label */
  480.           invert_label(1, &menuitems[i]);
  481.         }
  482.           }
  483.           else{                /* button up */
  484.         if(oindex != -1){
  485.           if(i == oindex){
  486.             *ch = menuitems[i].val;
  487.             rv = 1;
  488.           }
  489.         }
  490.           }
  491.         }
  492.         
  493.         if(!(newbut&k) && oindex != -1) {
  494.           invert_label(0, &menuitems[oindex]);    /* restore label */
  495.         }
  496.       }
  497.       
  498.       oldbut = newbut;
  499.       return(rv);
  500.     }
  501.     ++button;
  502.       }
  503.     }
  504.   }
  505.   return(FALSE);
  506. }
  507.  
  508.  
  509. /*
  510.  * invert_label - highlight the label of the given menu item.
  511.  */
  512. void
  513. invert_label(state, m)
  514. int state;
  515. MENUITEM *m;
  516. {
  517.   USHORT r, c;
  518.   VIOCURSORINFO oldInfo, newInfo;
  519.   int i, j, p;
  520.   char *lp;
  521.   int old_state = getrevstate();
  522.  
  523.   if(m->val == mnoop)
  524.     return;
  525.  
  526.   VioGetCurPos(&r, &c, 0);
  527.   VioGetCurType(&oldInfo, 0);
  528.   newInfo = oldInfo;
  529.   newInfo.attr = (USHORT)-1;
  530.   VioSetCurType(&newInfo, 0);             /* Hide Cursor */
  531.   (*term.t_move)(m->tl.r, m->tl.c);
  532.   (*term.t_rev)(state);
  533.   for(i = m->tl.r; i <= m->br.r; i++)
  534.     for(j = m->tl.c; j <= m->br.c; j++)
  535.       if(i == m->lbl.r && j == m->lbl.c){    /* show label?? */
  536.     lp = m->label;
  537.     while(*lp && j++ < m->br.c)
  538.       (*term.t_putchar)(*lp++);
  539.     continue;
  540.       }
  541.       else (*term.t_putchar)(' ');
  542.   
  543.   (*term.t_rev)(old_state);
  544.   VioSetCurPos(r, c, 0);    /* restore old position */
  545.   VioSetCurType(&oldInfo, 0);    /* Show Cursor */
  546.   vidUpdate();
  547. }
  548. #endif    /* MOUSE */
  549.  
  550.  
  551. /*
  552.  * alt_editor - fork off an alternate editor for mail message composition
  553.  */
  554. #define MAXARGS 10
  555. alt_editor(f, n)
  556. {
  557.   char   *fn;                    /* tmp holder for file name */
  558.   char   *cp;
  559.   char   *writetmp();
  560.   int    child, rc, i, done = 0;
  561.   long   l;
  562.   int    stat;
  563.   FILE   *p;
  564.  
  565.   char *args[MAXARGS];            /* ptrs into edit command */
  566.   char eb[NLINE];
  567.  
  568.   if(Pmaster == NULL)
  569.     return(-1);
  570.  
  571.   if(gmode&MDSCUR){
  572.     emlwrite("Alternate editor not available in restricted mode", NULL);
  573.     return(-1);
  574.   }
  575.  
  576.   if(Pmaster->alt_ed == NULL){
  577.     if (!(gmode&MDADVN)) {
  578.       emlwrite("\007Unknown Command",NULL);
  579.       return(-1);
  580.     }
  581.  
  582.     if((cp=getenv("VISUAL"))!=0 || (cp=getenv("EDITOR"))!=0)
  583.       strcpy(eb, (char *)getenv("EDITOR"));
  584.     else *eb = '\0';
  585.     
  586.     while(!done) {
  587.       rc = mlreplyd("Which alternate editor ? ",eb,NLINE,QDEFLT,NULL);
  588.  
  589.       switch(rc) {
  590.       case ABORT:
  591.     return(-1);
  592.       case HELPCH:
  593.     emlwrite("no alternate editor help yet", NULL);
  594.     
  595.     /* take sleep and break out after there's help */
  596.     sleep(3);
  597.     break;
  598.       case (CTRL|'L'):
  599.     sgarbf = TRUE;
  600.       update();
  601.       break;
  602.       case TRUE:
  603.       case FALSE:            /* does editor exist ? */
  604.     if(*eb == '\0'){        /* leave silently? */
  605.       mlerase();
  606.       return(-1);
  607.     }
  608.  
  609.     done++;
  610.     break;
  611.       default:
  612.     break;
  613.       }
  614.     }
  615.   }
  616.   else
  617.     strcpy(eb, Pmaster->alt_ed);
  618.  
  619.   if((fn=writetmp(0, 1)) == NULL){        /* get temp file */
  620.     emlwrite("Problem writing temp file for alt editor", NULL);
  621.     return(-1);
  622.   }
  623.  
  624.   strcat(eb, " ");
  625.   strcat(eb, fn);
  626.  
  627.   cp = eb;
  628.   for(i=0; *cp != '\0';i++) {            /* build args array */
  629.     if(i < MAXARGS) {
  630.       args[i] = NULL;            /* in case we break out */
  631.     }
  632.     else{
  633.       emlwrite("Too many args for command!", NULL);
  634.       return(-1);
  635.     }
  636.  
  637.     while(isspace((unsigned char)(*cp)))
  638.       if(*cp != '\0')
  639.     cp++;
  640.       else break;
  641.  
  642.     args[i] = cp;
  643.     while(!isspace((unsigned char)(*cp)))
  644.       if(*cp != '\0')
  645.     cp++;
  646.       else
  647.     break;
  648.     
  649.     if(*cp != '\0')
  650.       *cp++ = '\0';
  651.   }
  652.  
  653.   args[i] = NULL;
  654.  
  655.   (*Pmaster->raw_io)(0);            /* turn OFF raw mode */
  656.  
  657.   emlwrite("Invoking alternate editor...", NULL);
  658.  
  659.   {
  660.     void (*ohup)() = signal(SIGHUP, SIG_IGN);    /* ignore signals for now */
  661.     void (*oint)() = signal(SIGINT, SIG_IGN);
  662.     cp=args[0];
  663.     rc = spawnvp(P_WAIT, cp, args);
  664.     signal(SIGHUP, ohup);    /* restore signals */
  665.     signal(SIGINT, oint);
  666.   }
  667.  
  668.   (*Pmaster->raw_io)(1);        /* turn ON raw mode */
  669.   dont_interrupt();
  670.  
  671.   if (rc==-1) {  /* Can't run it */
  672.       emlwrite("error attempting to run alt editor", NULL);
  673.   }
  674.   /*
  675.    * replace edited text with new text 
  676.    */
  677.   else{
  678.     rc = 0;
  679.     curbp->b_flag &= ~BFCHG;        /* make sure old text gets blasted */
  680.     readin(fn, 0);            /* read new text overwriting old */
  681.     curbp->b_flag |= BFCHG;        /* mark dirty for packbuf() */
  682.   }
  683.   unlink(fn);                /* blast temp file */
  684.  
  685.   ttopen();                /* reset the signals */
  686.   refresh(0, 1);            /* redraw */
  687.   return(rc);
  688. }
  689.  
  690.  
  691. /*
  692.  *  bktoshell - suspend and wait to be woken up
  693.  */
  694. bktoshell()        /* suspend MicroEMACS and wait to wake up */
  695. {
  696.   int i;
  697.   static char * shell = NULL;
  698.  
  699.   if (shell == NULL) {
  700.     char *p;
  701.     shell=getenv("SHELL");
  702.     if (!shell && !(shell=getenv("COMSPEC")))
  703.       shell="CMD.EXE";
  704.     if ((p = strdup(shell)) > 0) {
  705.       for (shell = p; (p = strchr(shell, '/')) != 0; )
  706.     *p = '\\';
  707.     }
  708.   }
  709.  
  710.   (*term.t_move)(term.t_nrow, 0);
  711.   (*term.t_eeol)();
  712.   exit_text_mode(NULL);
  713.   interrupt_ok();
  714.   if (system(shell) == -1)
  715.     emlwrite("Error loading %s", shell);
  716.   else refresh(0, 1);            /* redraw */
  717.   enter_text_mode(NULL);
  718.   dont_interrupt();
  719. }
  720.  
  721.  
  722. /*
  723.  * P_open - run the given command in a sub-shell returning a file pointer
  724.  *        from which to read the output
  725.  *
  726.  * note:
  727.  *    For OS's other than unix, you will have to rewrite this function.
  728.  *    Hopefully it'll be easy to exec the command into a temporary file, 
  729.  *    and return a file pointer to that opened file or something.
  730.  */
  731. FILE *P_open(c)
  732. char *c;
  733. {
  734.   return(popen(c,"r"));
  735. }
  736.  
  737.  
  738.  
  739. /*
  740.  * P_close - close the given descriptor
  741.  *
  742.  */
  743. P_close(fp)
  744. FILE *fp;
  745. {
  746.   return(pclose(fp));
  747. }
  748.  
  749. /*
  750.  * A replacement for fflush
  751.  * relies on #define fflush os2_fflush
  752.  */
  753. #undef fflush
  754. int
  755. os2_fflush (FILE *f)
  756. {
  757.   if (f == stdout) {
  758.     vidUpdate();
  759.   }
  760.   else
  761.     fflush (f);
  762. }
  763.  
  764. /*
  765.  * ttresize - recompute the screen dimensions if necessary, and then
  766.  *          adjust pico's internal buffers accordingly
  767.  */
  768. int
  769. ttresize ()
  770. {
  771.     return (0);            /* no op */
  772. }
  773.  
  774. /*
  775.  * picosigs - Install any handlers for the signals we're interested
  776.  *          in catching.
  777.  */
  778. picosigs()
  779. {
  780.     signal(SIGHUP,  do_hup_signal);    /* deal with SIGHUP */
  781.     signal(SIGTERM, do_hup_signal);    /* deal with SIGTERM */
  782. }
  783.  
  784. /*
  785.  * do_hup_signal - jump back in the stack to where we can handle this
  786.  */
  787. void
  788. do_hup_signal(int sig)
  789. {
  790.   sig=sig;
  791.   signal(SIGHUP,  SIG_IGN);            /* ignore further SIGHUP's */
  792.   signal(SIGTERM, SIG_IGN);            /* ignore further SIGTERM's */
  793.   if(Pmaster){
  794.     extern jmp_buf finstate;
  795.  
  796.     longjmp(finstate, COMP_GOTHUP);
  797.   }
  798.   else{
  799.     /*
  800.      * if we've been interrupted and the buffer is changed,
  801.      * save it...
  802.      */
  803.     if(anycb() == TRUE){            /* time to save */
  804.       if(curbp->b_fname[0] == '\0'){    /* name it */
  805.     strcpy(curbp->b_fname, "pico.sav");
  806.       }
  807.       else{
  808.     strcat(curbp->b_fname, ".sav");
  809.       }
  810.       writeout(curbp->b_fname);
  811.     }
  812.     vttidy();
  813.     exit(1);
  814.   }
  815. }
  816.  
  817.  
  818.  
  819. #ifdef    MOUSE
  820.  
  821. /*
  822.  * end_mouse - a no-op on DOS/Windows
  823.  */
  824. void
  825. end_mouse()
  826. {
  827. }
  828.  
  829.  
  830. /*
  831.  * mouseexist - function to let outsiders know if mouse is turned on
  832.  *              or not.
  833.  */
  834. mouseexist()
  835. {
  836.     return(mexist);
  837. }
  838. #endif    /* MOUSE */
  839.  
  840.  
  841. /*
  842.  * fallowc - returns TRUE if c is allowable in filenames, FALSE otw
  843.  */
  844. fallowc(c)
  845. int c;
  846. {
  847.   return(okinfname[c>>3] & 0x80>>(c&7));
  848. }
  849.  
  850.  
  851. /*
  852.  * fexist - returns TRUE if the file exists, FALSE otherwise
  853.  */
  854. fexist(file, m, l)
  855. char *file, *m;
  856. long *l;
  857. {
  858.   struct stat    sbuf;
  859.  
  860.   if(l != NULL)
  861.     *l = 0L;
  862.  
  863.   if(stat(file, &sbuf) < 0){
  864.     if(ENOENT)                /* File not found */
  865.       return(FIOFNF);
  866.     else
  867.       return(FIOERR);
  868.   }
  869.  
  870.   if(l != NULL)
  871.     *l = sbuf.st_size;
  872.  
  873.   if(sbuf.st_mode & S_IFDIR)
  874.     return(FIODIR);
  875.  
  876.   if(m[0] == 'r')                /* read access? */
  877.     return((S_IREAD & sbuf.st_mode) ? FIOSUC : FIONRD);
  878.   else if(m[0] == 'w')            /* write access? */
  879.     return((S_IWRITE & sbuf.st_mode) ? FIOSUC : FIONWT);
  880.   else if(m[0] == 'x')            /* execute access? */
  881.     return((S_IEXEC & sbuf.st_mode) ? FIOSUC : FIONEX);
  882.   return(FIOERR);                /* what? */
  883. }
  884.  
  885.  
  886. /*
  887.  * isdir - returns true if fn is a readable directory, false otherwise
  888.  *         silent on errors (we'll let someone else notice the problem;)).
  889.  */
  890. isdir(fn, l)
  891. char *fn;
  892. long *l;
  893. {
  894.   struct stat sbuf;
  895.  
  896.   if(l)
  897.     *l = 0;
  898.  
  899.   if(stat(fn, &sbuf) < 0)
  900.     return(0);
  901.  
  902.   if(l)
  903.     *l = sbuf.st_size;
  904.  
  905.   return(sbuf.st_mode & S_IFDIR);
  906. }
  907.  
  908.  
  909. /*
  910.  * gethomedir - returns the users home directory
  911.  *              Note: home is malloc'd for life of pico
  912.  */
  913. char *gethomedir(l)
  914. int *l;
  915. {
  916.   static char *home = NULL;
  917.   static short hlen = 0;
  918.  
  919.   if(home == NULL){
  920.     char *p, buf[NLINE];
  921.  
  922.     if (home=getenv("PINEHOME"))       /* Overrides all others */
  923.       strcpy(buf, home);
  924.     else if (home=getenv("HOME"))       /* Convenient group placement */
  925.       strcpy(buf, home);
  926.     else if (home=getenv("ETC"))       /* IBM TCPIP */
  927.       strcpy(buf, home);
  928.     else sprintf(buf, "%c:\\", _getdrive());
  929.     hlen = strlen(buf);
  930.     if ((home=(char *)malloc(hlen + 1)) == NULL) {
  931.       emlwrite("Problem allocating space for home dir", NULL);
  932.       return(0);
  933.     }
  934.     strcpy(home, buf);
  935.     while ((p=strchr(home,'/')) != NULL)   /* Normalise, just in case */
  936.       *p = '\\';
  937.   }
  938.  
  939.   if(l)
  940.     *l = hlen;
  941.  
  942.   return(home);
  943. }
  944.  
  945.  
  946. /*
  947.  * homeless - returns true if given file does not reside in the current
  948.  *            user's home directory tree. 
  949.  */
  950. homeless(f)
  951. char *f;
  952. {
  953.   char *home;
  954.   int   len;
  955.  
  956.   home = gethomedir(&len);
  957.   return(strncmp(home, f, len));
  958. }
  959.  
  960.  
  961.  
  962. /*
  963.  * errstr - return system error string corresponding to given errno
  964.  *          Note: strerror() is not provided on all systems, so it's 
  965.  *          done here once and for all.
  966.  */
  967. char *errstr(err)
  968. int err;
  969. {
  970.   return((err >= 0 && err < sys_nerr) ? (char*)sys_errlist[err] : NULL);
  971. }
  972.  
  973.  
  974. /*
  975.  * getfnames - return all file names in the given directory in a single 
  976.  *             malloc'd string.  n contains the number of names
  977.  */
  978. char *getfnames(dn, pat, n, e)
  979. char *dn, *pat, *e;
  980. int  *n;
  981. {
  982.     int status;
  983.     long l;
  984.     char *names, *np, *p;
  985.     char buf[NLINE];
  986.     struct stat sbuf;
  987.     ULONG count=1;
  988.     FILEFINDBUF3 findbuf;
  989.     HDIR hdir=HDIR_CREATE;
  990.  
  991.     *n = 0;
  992.  
  993.     while ((p = strchr(dn, '/')) != NULL)
  994.       *p = '\\';
  995.  
  996.     if(stat(dn, &sbuf) < 0){
  997.     if(e)
  998.       sprintf(e, "\007Dir \"%s\": %s", dn, strerror(errno));
  999.  
  1000.     return(NULL);
  1001.     } 
  1002.     else{
  1003.     l = sbuf.st_size;
  1004.     if(!(sbuf.st_mode & S_IFDIR)){
  1005.         if(e)
  1006.           sprintf(e, "\007Not a directory: \"%s\"", dn);
  1007.  
  1008.         return(NULL);
  1009.     }
  1010.     }
  1011.  
  1012.     if((names=(char *)malloc(sizeof(char)*3072)) == NULL){
  1013.     if(e)
  1014.     sprintf(e, "\007Can't malloc space for file names", NULL);
  1015.  
  1016.     return(NULL);
  1017.     }
  1018.  
  1019.     np = names;
  1020.  
  1021.     strcpy(buf, dn);
  1022.     if (*buf && buf[strlen(buf)-1] != '\\')
  1023.       strcat(buf, "\\");
  1024.     if (pat && *pat)
  1025.       strcat(buf, pat);
  1026.     if (!pat || !*pat || strchr(pat, '.')==NULL)
  1027.       strcat(buf, "*");
  1028.  
  1029.     if (DosFindFirst(buf, &hdir, FILE_NORMAL|FILE_DIRECTORY, &findbuf,
  1030.              sizeof findbuf, &count, FIL_STANDARD) != 0) {
  1031.     if(e)
  1032.       sprintf(e, "Can't find first file in \"%s\"", dn);
  1033.  
  1034.     free((char *) names);
  1035.     return(NULL);
  1036.     }
  1037.  
  1038.     do{
  1039.     (*n)++;
  1040.     p = findbuf.achName;
  1041.     while((*np++ = *p++) != '\0')
  1042.       ;
  1043.     }
  1044.     while(DosFindNext(hdir, &findbuf, sizeof findbuf, &count) == 0);
  1045.  
  1046.     return(names);
  1047. }
  1048.  
  1049.  
  1050. /*
  1051.  * fioperr - given the error number and file name, display error
  1052.  */
  1053. void
  1054. fioperr(e, f)
  1055. int  e;
  1056. char *f;
  1057. {
  1058.   switch(e){
  1059.   case FIOFNF:                /* File not found */
  1060.     emlwrite("\007File \"%s\" not found", f);
  1061.     break;
  1062.   case FIOEOF:                /* end of file */
  1063.     emlwrite("\007End of file \"%s\" reached", f);
  1064.     break;
  1065.   case FIOLNG:                /* name too long */
  1066.     emlwrite("\007File name \"%s\" too long", f);
  1067.     break;
  1068.   case FIODIR:                /* file is a directory */
  1069.     emlwrite("\007File \"%s\" is a directory", f);
  1070.     break;
  1071.   case FIONWT:
  1072.     emlwrite("\007Write permission denied: %s", f);
  1073.     break;
  1074.   case FIONRD:
  1075.     emlwrite("\007Read permission denied: %s", f);
  1076.     break;
  1077.   case FIONEX:
  1078.     emlwrite("\007Execute permission denied: %s", f);
  1079.     break;
  1080.   default:
  1081.     emlwrite("\007File I/O error: %s", f);
  1082.   }
  1083. }
  1084.  
  1085.  
  1086. /*
  1087.  * pfnexpand - pico's function to expand the given file name if there is 
  1088.  *           a leading '~'
  1089.  */
  1090. char *pfnexpand(fn, len)
  1091. char *fn;
  1092. int  len;
  1093. {
  1094.   register char *x, *y, *z;
  1095.   char *home = gethomedir(NULL);
  1096.   char name[20];
  1097.  
  1098.   if(*fn == '~') {
  1099.     for(x = fn+1, y = name; *x != '/' && *x != '\\' && *x != '\0'; *y++ = *x++);
  1100.     *y = '\0';
  1101.     if(strlen(home) + strlen(fn) > len) {
  1102.       return(NULL);
  1103.     }
  1104.     /* make room for expanded path */
  1105.     for(z=x+strlen(x),y=fn+strlen(x)+strlen(home);
  1106.         z >= x;
  1107.         *y-- = *z--);
  1108.     /* and insert the expanded address */
  1109.     for(x=fn,y=home; *y != '\0'; *x++ = *y++);
  1110.   }
  1111.  
  1112.   return(fn);
  1113. }
  1114.  
  1115. getcurdir(drv, buf)
  1116. int drv;
  1117. char *buf;
  1118. {
  1119.   LONG ml = _MAX_PATH;
  1120.   drv = drv ? toupper(drv) : _getdrive();
  1121.   buf[0] = (char)drv;
  1122.   buf[1] = ':';
  1123.   buf[2] = '\\';
  1124.   return DosQueryCurrentDir(drv-'A'+1, buf + 3, &ml) == 0;
  1125. }
  1126.  
  1127. /*
  1128.  * fixpath - make the given pathname into an absolute path
  1129.  */
  1130. fixpath(name, len)
  1131. char *name;
  1132. int  len;
  1133. {
  1134.   char *p;
  1135.   char file[_MAX_PATH];
  1136.   int  dr;
  1137.  
  1138.   if(!len)
  1139.     return(0);
  1140.  
  1141.   /* normalize: xlate any '/' into '\\' */
  1142.   while ((p=strchr(name,'/'))!=NULL)
  1143.     *p='\\';
  1144.  
  1145.   /* return the full path of given file */
  1146.   if(isalpha((unsigned char)name[0]) && name[1] == ':'){ /* have drive spec? */
  1147.     if(name[2] == '\\')                 /* including path? */
  1148.       return 1;
  1149.     if (!getcurdir(name[0], file))
  1150.       return 0;
  1151.     name += 2;
  1152.   }
  1153.   else if(name[0] == '.' && (!name[1] || name[1] == '\\')) {
  1154.     getcurdir(0, file);
  1155.     name += (1 + name[1] == '\\');
  1156.   }
  1157.   else if(name[0] == '\\') {        /* no drive spec! */
  1158.     file[0] = (char)_getdrive();
  1159.     file[1] = ':';
  1160.     file[2] = '\0';
  1161.   }
  1162.   else getcurdir(0, file);    /* no qualification */
  1163.   
  1164.   if(*name) {                /* if name, append it */
  1165.     p = NULL;
  1166.     if (name[0] == '.' && name[1] == '.' && (!name[2] || name[2] == '\\')) {
  1167.       if ((p = strrchr(name,'\\'))!=NULL) {
  1168.         *p++ = '\0';
  1169.         if (!*p && (p=strrchr(name,'\\'))!=NULL)
  1170.           *p = '\0';
  1171.       }
  1172.       name += (2 & name[2] == '\\');
  1173.     }
  1174.     if (*name) {
  1175.       if (name[0] == '.' && (!name[1] || name[1] == '\\'))
  1176.         name += (1 + name[1] == '\\');
  1177.       if (*name) {
  1178.         if (*file && file[strlen(file)-1] != '\\' && *name != '\\')
  1179.           strcat(file, "\\");
  1180.         strcat(file, name);
  1181.       }
  1182.     }
  1183.   }
  1184.  
  1185.   strncpy(name, file, len);            /* copy back to real buffer */
  1186.   name[len-1] = '\0';                /* tie off just in case */
  1187.   return(1);
  1188. }
  1189.  
  1190.  
  1191. /*
  1192.  * compresspath - given a base path and an additional directory, collapse
  1193.  *                ".." and "." elements and return absolute path (appending
  1194.  *                base if necessary).  
  1195.  *
  1196.  *                returns  1 if OK, 
  1197.  *                         0 if there's a problem
  1198.  *                         new path, by side effect, if things went OK
  1199.  */
  1200. compresspath(base, path, len)
  1201. char *base, *path;
  1202. int  len;
  1203. {
  1204.   register int i;
  1205.   int  depth = 0;
  1206.   char *p;
  1207.   char *stack[32];
  1208.   char  pathbuf[NLINE];
  1209.  
  1210. #define PUSHD(X)  (stack[depth++] = X)
  1211. #define POPD()    ((depth > 0) ? stack[--depth] : "")
  1212.  
  1213.   strcpy(pathbuf, path);
  1214.   fixpath(pathbuf, len);
  1215.  
  1216.   p = pathbuf;
  1217.   for(i=0; pathbuf[i] != '\0'; i++){        /* pass thru path name */
  1218.     if(pathbuf[i] == C_FILESEP){
  1219.       if(p != pathbuf)
  1220.         PUSHD(p);                /* push dir entry */
  1221.       p = &pathbuf[i+1];            /* advance p */
  1222.       pathbuf[i] = '\0';            /* cap old p off */
  1223.       continue;
  1224.     }
  1225.  
  1226.     if(pathbuf[i] == '.'){            /* special cases! */
  1227.       if(pathbuf[i+1] == '.'            /* parent */
  1228.          && (pathbuf[i+2] == C_FILESEP || pathbuf[i+2] == '\0')){
  1229.         if(!strcmp(POPD(),""))        /* bad news! */
  1230.           return(0);
  1231.  
  1232.         i += 2;
  1233.         p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
  1234.       }
  1235.       else if(pathbuf[i+1] == C_FILESEP || pathbuf[i+1] == '\0'){
  1236.         i++;
  1237.         p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
  1238.       }
  1239.     }
  1240.   }
  1241.  
  1242.   if(*p != '\0')
  1243.     PUSHD(p);                    /* get last element */
  1244.  
  1245.   path[0] = '\0';
  1246.   for(i = 0; i < depth; i++){
  1247.     strcat(path, S_FILESEP);
  1248.     strcat(path, stack[i]);
  1249.   }
  1250.  
  1251.   return(1);                    /* everything's ok */
  1252. }
  1253.  
  1254.  
  1255. /*
  1256.  * tmpname - return a temporary file name in the given buffer
  1257.  */
  1258. void
  1259. tmpname(name)
  1260. char *name;
  1261. {
  1262.   static int counter = 0;
  1263.   static char *tmpdir;
  1264.   char * p;
  1265.   if (!tmpdir && (tmpdir=getenv("TEMP"))==NULL && (tmpdir = getenv("TMP"))==NULL)
  1266.     tmpdir=".";
  1267.   p = strchr(strcpy(name, tmpdir), '/');
  1268.   while (p != NULL)
  1269.   {
  1270.     *p++ = '\\';
  1271.     p = strchr(p, '/');
  1272.   }
  1273.   p = strrchr(name, '\\');
  1274.   if (p == 0)
  1275.     p = name + strlen(name);
  1276.   else if (*++p != 0)
  1277.   {
  1278.     p = name + strlen(name);
  1279.     *p++ = '\\';
  1280.   }
  1281.   sprintf(p, "pn%d%d", getpid(), ++counter);
  1282. }
  1283.  
  1284.  
  1285. /*
  1286.  * Take a file name, and from it
  1287.  * fabricate a buffer name. This routine knows
  1288.  * about the syntax of file names on the target system.
  1289.  * I suppose that this information could be put in
  1290.  * a better place than a line of code.
  1291.  */
  1292. void
  1293. makename(bname, fname)
  1294. char    bname[];
  1295. char    fname[];
  1296. {
  1297.   register char   *cp1;
  1298.   register char   *cp2;
  1299.  
  1300.   cp1 = &fname[0];
  1301.   while (*cp1 != 0)
  1302.     ++cp1;
  1303.  
  1304.   while (cp1!=&fname[0] && cp1[-1]!='\\')
  1305.     --cp1;
  1306.   cp2 = &bname[0];
  1307.   while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  1308.     *cp2++ = *cp1++;
  1309.   *cp2 = 0;
  1310. }
  1311.  
  1312.  
  1313. /*
  1314.  * copy - copy contents of file 'a' into a file named 'b'.  Return error
  1315.  *        if either isn't accessible or is a directory
  1316.  */
  1317. copy(a, b)
  1318. char *a, *b;
  1319. {
  1320.   int    n, rv = 0;
  1321.   struct stat tsb, fsb;
  1322.  
  1323.   if(stat(a, &fsb) < 0){        /* get source file info */
  1324.     emlwrite("Can't Copy: %s", errstr(errno));
  1325.     return(-1);
  1326.   }
  1327.  
  1328.   if(!(fsb.st_mode&S_IREAD)){        /* can we read it? */
  1329.     emlwrite("\007Read permission denied: %s", a);
  1330.     return(-1);
  1331.   }
  1332.  
  1333.   if((fsb.st_mode&S_IFMT) == S_IFDIR){ /* is it a directory? */
  1334.     emlwrite("\007Can't copy: %s is a directory", a);
  1335.     return(-1);
  1336.   }
  1337.  
  1338.   if(stat(b, &tsb) < 0){        /* get dest file's mode */
  1339.     switch(errno){
  1340.     case ENOENT:
  1341.       break;            /* these are OK */
  1342.     default:
  1343.       emlwrite("\007Can't Copy: %s", errstr(errno));
  1344.       return(-1);
  1345.     }
  1346.   }
  1347.   else{
  1348.     if(!(tsb.st_mode&S_IWRITE)){    /* can we write it? */
  1349.       emlwrite("\007Write permission denied: %s", b);
  1350.       return(-1);
  1351.     }
  1352.  
  1353.     if((tsb.st_mode&S_IFMT) == S_IFDIR){    /* is it directory? */
  1354.       emlwrite("\007Can't copy: %s is a directory", b);
  1355.       return(-1);
  1356.     }
  1357.  
  1358.     if(fsb.st_dev == tsb.st_dev && fsb.st_ino == tsb.st_ino){
  1359.       emlwrite("\007Identical files.  File not copied", NULL);
  1360.       return(-1);
  1361.     }
  1362.   }
  1363.  
  1364.   rv=DosCopy(a, b, DCPY_EXISTING);
  1365.  
  1366.   if(rv != 0 < 0){
  1367.     emlwrite("Copy Failed: DosCopy() error %d", rv);
  1368.     return(-1);
  1369.   }
  1370.   return(rv);
  1371. }
  1372.  
  1373.  
  1374. /*
  1375.  * Open a file for writing. Return TRUE if all is well, and FALSE on error
  1376.  * (cannot create).
  1377.  */
  1378. ffwopen(fn)
  1379. char    *fn;
  1380. {
  1381.   extern FILE *ffp;
  1382.  
  1383.   if ((ffp=fopen(fn, "w")) == NULL) {
  1384.     emlwrite("Cannot open file for writing", NULL);
  1385.     return (FIOERR);
  1386.   }
  1387.   return (FIOSUC);
  1388. }
  1389.  
  1390.  
  1391. /*
  1392.  * Close a file. Should look at the status in all systems.
  1393.  */
  1394. ffclose()
  1395. {
  1396.   extern FILE *ffp;
  1397.  
  1398.   if (fclose(ffp) != FALSE) {
  1399.     emlwrite("Error closing file", NULL);
  1400.     return(FIOERR);
  1401.   }
  1402.  
  1403.   return(FIOSUC);
  1404. }
  1405.  
  1406.  
  1407. /*
  1408.  * ffelbowroom - make sure the destination's got enough room to receive
  1409.  *         what we're about to write...
  1410.  */
  1411. ffelbowroom(fn)
  1412. char    *fn;
  1413. {
  1414.     return(TRUE);
  1415. }
  1416.  
  1417.  
  1418. /*
  1419.  * worthit - generic sort of test to roughly gage usefulness of using 
  1420.  *           optimized scrolling.
  1421.  *
  1422.  * note:
  1423.  *    returns the line on the screen, l, that the dot is currently on
  1424.  */
  1425. worthit(l)
  1426. int *l;
  1427. {
  1428.   int i;            /* l is current line */
  1429.   unsigned below;        /* below is avg # of ch/line under . */
  1430.  
  1431.   *l = doton(&i, &below);
  1432.   below = (i > 0) ? below/(unsigned)i : 0;
  1433.  
  1434.   return(below > 3);
  1435. }
  1436.  
  1437.  
  1438. /*
  1439.  * o_insert - optimize screen insert of char c
  1440.  */
  1441. o_insert(c)
  1442. char c;
  1443. {
  1444.   return(0);
  1445. }
  1446.  
  1447.  
  1448. /*
  1449.  * o_delete - optimized character deletion
  1450.  */
  1451. o_delete()
  1452. {
  1453.   return(0);
  1454. }
  1455.  
  1456.  
  1457. /*
  1458.  * pico_new_mail - just checks mtime and atime of mail file and notifies user 
  1459.  *               if it's possible that they have new mail.
  1460.  */
  1461. pico_new_mail()
  1462. {
  1463.   return(0);
  1464. }
  1465.  
  1466.  
  1467.  
  1468. /*
  1469.  * time_to_check - checks the current time against the last time called 
  1470.  *                 and returns true if the elapsed time is > timeout
  1471.  */
  1472. time_to_check()
  1473. {
  1474.   static time_t lasttime = 0L;
  1475.  
  1476.   if(!timeout)
  1477.     return(FALSE);
  1478.  
  1479.   if(time((long *) 0) - lasttime > (time_t)timeout){
  1480.     lasttime = time((long *) 0);
  1481.     return(TRUE);
  1482.   }
  1483.   else
  1484.     return(FALSE);
  1485. }
  1486.  
  1487.  
  1488. /*
  1489.  * sstrcasecmp - compare two pointers to strings case independently
  1490.  */
  1491. sstrcasecmp(s1, s2)
  1492. QcompType *s1, *s2;
  1493. {
  1494.   return(stricmp(*(char **)s1, *(char **)s2));
  1495. }
  1496.  
  1497.  
  1498. /*
  1499.  * sleep the given number of microseconds
  1500.  */
  1501. ssleep(s)
  1502.     clock_t s;
  1503. {
  1504.   s += clock();
  1505.   while(s > clock())
  1506.     ;
  1507. }
  1508.  
  1509.  
  1510. /*
  1511.  * chkptinit -- initialize anything we need to support composer
  1512.  *        checkpointing
  1513.  */
  1514. chkptinit(file, n)
  1515.     char *file;
  1516.     int   n;
  1517. {
  1518.     if(!file[0]){
  1519.     long gmode_save = gmode;
  1520.  
  1521.     if(gmode&MDCURDIR)
  1522.       gmode &= ~MDCURDIR;  /* so fixpath will use home dir */
  1523.  
  1524.     strcpy(file, "#picoTM0.txt");
  1525.     fixpath(file, NLINE);
  1526.     gmode = gmode_save;
  1527.     }
  1528.     else{
  1529.     int l = strlen(file);
  1530.  
  1531.     if(file[l-1] != '\\'){
  1532.         file[l++] = '\\';
  1533.         file[l]   = '\0';
  1534.     }
  1535.  
  1536.     strcpy(file + l, "#picoTM0.txt");
  1537.     }
  1538.  
  1539.     if(fexist(file, "r", NULL) == FIOSUC){ /* does file exist? */
  1540.     char copy[NLINE];
  1541.  
  1542.     strcpy(copy, "#picoTM1.txt");
  1543.     fixpath(copy, NLINE);
  1544.     rename(file, copy);  /* save so we don't overwrite it */
  1545.     }
  1546.  
  1547.     unlink(file);
  1548. }
  1549.  
  1550.  
  1551. static USHORT myShift = 0;
  1552.  
  1553. int kbd_ready()
  1554. {
  1555.   KBDKEYINFO ki;
  1556.  
  1557.   if (KbdPeek(&ki, 0)==0)
  1558.   {
  1559.     if (ki.fbStatus & 0x40) {
  1560.       int key = (USHORT)((ki.chScan << 8) | ki.chChar);
  1561.       myShift = ki.fsState;
  1562.       if (!key && ki.fbStatus & 0x01) {
  1563.         KbdCharIn(&ki, IO_WAIT, 0);
  1564.       }
  1565.       return key;
  1566.     }
  1567.   }
  1568.   return 0;
  1569. }
  1570.  
  1571. int kbd_getkey()
  1572. {
  1573.   KBDKEYINFO ki;
  1574.   
  1575.   while (KbdCharIn(&ki, IO_WAIT, 0)==0) {
  1576.     if (ki.fbStatus & 0x40) {
  1577.       myShift = ki.fsState;
  1578.       return (USHORT)((ki.chScan << 8) | ki.chChar);
  1579.     }
  1580.     if (ki.fbStatus & 0x01) {
  1581.       myShift = ki.fsState;
  1582.     }
  1583.   }
  1584.   
  1585.   return NODATA;
  1586. }
  1587.  
  1588. void kbd_flush()
  1589. {
  1590.   KbdFlushBuffer(0);
  1591. }
  1592.  
  1593. int kbd_shift()
  1594. {
  1595.   return myShift;
  1596. }
  1597.